
#include "ChessControllerImpl.h"
#include <set>

ChessControllerImpl::ChessControllerImpl() {
   Initialize();
}

ChessControllerImpl::~ChessControllerImpl () {
   Destroy();
}

/**
   * Indicate to the player that the user clicked on the given
   * row and column with the mouse.
   */
void ChessControllerImpl::on_CellSelected(int row, int col, int button) {
   BoardPosition pos(row,col);
   Piece * curPiece = model->on_CellSelected(pos);

   if (pos == highPos)
      return;

   //Perhaps interface with the Player classes a bit more?
   Piece * oldPiece = model->on_CellSelected(highPos);
   if (oldPiece != NULL && !IsPlayersPiece(curPiece)) {

      // Something about only moving to the legalmoves from here
      std::set<BoardPosition>::iterator it;
      std::set<BoardPosition> valids = oldPiece->GetLegalMoves(model->GetBoard(), highPos);
      it = valids.find(pos);
      if (it == valids.end()) {
         view->HighlightSquare(highPos.GetRow(), highPos.GetCol(), GREEN_SQUARE);
         return;
      }

      //Piece was taken
      if (curPiece != NULL)
         model->AddOffBoard(curPiece);

      Move m(highPos, pos, oldPiece, curPiece);
      model->AddMove(m);
      model->AddPiece(pos, model->RemovePiece(highPos));
      DrawSquare(highPos);
      highPos.Reset();
      UnHighlightAll();
      NextPlayer();
   }
   else if (curPiece != NULL) {
      if (IsPlayersPiece(curPiece)) {

         UnHighlightAll();

         std::set<BoardPosition>::iterator it;

         std::set<BoardPosition> valids = curPiece->GetLegalMoves(model->GetBoard(), pos);

         for (it = valids.begin(); it!= valids.end(); it++ ) {
            view->HighlightSquare( (*it).GetRow(), (*it).GetCol(), WHITE_SQUARE);
         }

         highPos = pos;
         view->HighlightSquare(row, col, GREEN_SQUARE);
      }
   }

   DrawSquare(pos);

}

void ChessControllerImpl::UnHighlightAll() {
   for (int i=0; i<8; i++) {
      for (int j=0; j<8; j++) {
         view->UnHighlightSquare(i,j);
      }
   }
}

bool ChessControllerImpl::IsPlayersPiece(Piece * curPiece) {
   return curPiece != NULL ? !(curPiece->IsWhite() ^ IsWhiteTurn()) : false;
}


///@param row where drag began
///@param col where drag began
void ChessControllerImpl::on_DragStart(int row,int col) {
   on_CellSelected(row, col, 1);
}

///@param row where drag ended
///@param col where drag ended
///@return true if the drag resulted in a successful drop
bool ChessControllerImpl::on_DragEnd(int row,int col){
   on_CellSelected(row, col, 1);
   return true;
}

/**
   * Handle when the user selected the new game button.
   */
void ChessControllerImpl::on_NewGame() {
   Destroy();
   Initialize();
   DrawBoard();
}

/**
   * Handle when the user selected the save game button.
   */
void ChessControllerImpl::on_SaveGame() {
   model->on_SaveGame();
}

/**
   * Handle when the user selected the save game as button.
   */
void ChessControllerImpl::on_SaveGameAs() {
   model->on_SaveGameAs(view->SelectSaveFile());
}

/**
   * Handle when the user selected the load game button.
   */
void ChessControllerImpl::on_LoadGame() {
   model->on_LoadGame(view->SelectLoadFile());
}

/**
   * Handle when the user selected the undo move button.
   */
void ChessControllerImpl::on_UndoMove() {
   Move m = model->on_UndoMove();

   if (m.GetStartPos().GetCol() < 0)
      return;

   DrawSquare(m.GetStartPos());
   DrawSquare(m.GetEndPos());

   if (highPos.GetRow() != -1)
         view->UnHighlightSquare(highPos.GetRow(), highPos.GetCol());

   highPos.Reset();
   NextPlayer();
}

/**
   * Handle when the user selects to quit the game, either through the
   * quit button, the close X button, or the file menu.
   */
void ChessControllerImpl::on_QuitGame() {}

/**
   * Handle when a timer event has been signaled.
   */
void ChessControllerImpl::on_TimerEvent() {}

/**
   * Set the ChessView that this ChessController will handle inputs for.
   */
void ChessControllerImpl::SetView(ChessView * view) {
   this->view = view;
}

void ChessControllerImpl::DrawBoard() {

   for (int i=0; i<8; i++) {
      for (int j=0; j<8; j++) {
         BoardPosition pos(i,j);
         DrawSquare(pos);
      }
   }
}

void ChessControllerImpl::DrawSquare(BoardPosition pos) {
   Piece * curPiece = model->GetPiece(pos);
   if (curPiece != NULL) {
      view->PlacePiece(pos.GetRow(),pos.GetCol(),ImageName(GetType(*curPiece)));
   }
   else {
      view->ClearPiece(pos.GetRow(),pos.GetCol());
   }
}

int ChessControllerImpl::GetType(Piece & curPiece) {
   int toRet = 0;
   int white = 0;

   if (!curPiece.IsWhite()) {
      white++;
   }

   if (typeid(curPiece) == typeid(Pawn))
      toRet = 2;
   else if (typeid(curPiece) == typeid(Rook))
      toRet = 3;
   else if (typeid(curPiece) == typeid(Knight))
      toRet = 4;
   else if (typeid(curPiece) == typeid(Bishop))
      toRet = 5;
   else if (typeid(curPiece) == typeid(King))
      toRet = 6;
   else if (typeid(curPiece) == typeid(Queen))
      toRet = 7;

   return 2*toRet + white;
}

void ChessControllerImpl::Initialize() {
   model = new ChessModel();
   player1 = new HumanPlayer();
   player2 = new HumanPlayer();
   currentPlayer = player1;
}

void ChessControllerImpl::Destroy() {
   delete player1;
   delete player2;
   delete model;

   player1 = NULL;
   player2 = NULL;
   currentPlayer = NULL;
   model = NULL;
}